package net.zoneland.knowledge.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.gson.reflect.TypeToken;

import net.zoneland.knowledge.cache.RedisCacheUtil;
import net.zoneland.knowledge.constant.BizConstant;
import net.zoneland.knowledge.dao.DataCategoryMapper;
import net.zoneland.knowledge.dao.QuickNavMapper;
import net.zoneland.knowledge.enums.CacheEnum;
import net.zoneland.knowledge.enums.CmpDnEnum;
import net.zoneland.knowledge.enums.DictParentEnum;
import net.zoneland.knowledge.enums.RobotOrdersTypeEnum;
import net.zoneland.knowledge.model.DataCategory;
import net.zoneland.knowledge.model.DataCategoryExample;
import net.zoneland.knowledge.model.DictItem;
import net.zoneland.knowledge.model.LoginUserPojo;
import net.zoneland.knowledge.model.QuickNav;
import net.zoneland.knowledge.model.QuickNavExample;
import net.zoneland.knowledge.model.RobotInfo;
import net.zoneland.knowledge.service.ApiService;
import net.zoneland.knowledge.service.DictItemService;
import net.zoneland.knowledge.service.RobotInfoBiz;
import net.zoneland.knowledge.utils.GsonUtils;

/**
 * .
 *
 * @author: bcc
 * 2021/6/2
 */
@Service
public class ApiServiceImpl implements ApiService {

    /**
     * logger.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ApiServiceImpl.class);

    /**
     * guava缓存，获取内存.
     */
    private static final Cache<String, Object> cache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build();

    private static final String CACHE_CATEGORY = "category";

    @Autowired
    private DictItemService dictItemService;

    @Autowired
    private RedisCacheUtil redisCacheUtil;

    @Autowired
    private RobotInfoBiz robotInfoBiz;
    
    @Autowired
    private DataCategoryMapper dataCategoryMapper;

    @Autowired
    private QuickNavMapper quickNavMapper;


    @Override
    public RobotInfo getRobotInfo(final LoginUserPojo loginUserPojo, final boolean isCmpDn) throws Exception {
        String userId=loginUserPojo.getUserID();
        String cmpDn=loginUserPojo.getCompanyDN();
        //根据机器人名称的排序号获取信息
        HashMap<String,Integer> ordersMap = getRobotOrders(userId);
        RobotInfo robotInfo = getNewRobotInfo(true, loginUserPojo, isCmpDn);
        if(StringUtils.isBlank(robotInfo.getRobotName())){
            robotInfo = getNewRobotInfo(true, loginUserPojo, true);
        }

        //根据开场语的排序号获取开场语的信息
        String openingWord="";
        String openingType = RobotOrdersTypeEnum.TALK_OPENING.getValue();
        int openingOrder=ordersMap.get(openingType);
        //处理机器人名称中的开场语定制情况
        if (0==openingOrder) {
            if(StringUtils.isBlank(robotInfo.getOpeningWords())){
                //没有配置定制语直接从1开始
                openingOrder=1;
            }
        }
        if (openingOrder>0) {
            String dictName="";
            List<DictItem> dictItemList = dictItemService.findDictByParentId(DictParentEnum.TALK_OPENING_WORDS.getValue());
            if(openingOrder>0&&openingOrder<=dictItemList.size()){
                //根据排序号取到开场语配置模板，替换robotName
                dictName=dictItemList.get(openingOrder-1).getDictName();
            }else{
                dictName=dictItemList.get(0).getDictName();
            }
            openingWord = dictName.replaceAll(BizConstant.REPLACE_ROBOT_NAME, robotInfo.getRobotName());
            robotInfo.setOpeningWords(openingWord);
        }
        //顺便设置下一次的显示序号
        setRobotOrders(userId,cmpDn,ordersMap);
        return robotInfo;
    }

    /**
     * 获取当前登录人的机器人显示序号
     * @Author Pbody
     * @Date 20:51 2020/5/30
     * @Param [userId]
     * @return java.util.HashMap<java.lang.String,java.lang.Integer>
     **/
    private HashMap<String,Integer> getRobotOrders(String userId){
        HashMap<String,Integer> orderMap=new HashMap<>();
        //获取目前的显示序号
        String robotOrder=redisCacheUtil.hget(CacheEnum.ROBOT_WORDS_ORDERS.getValue(),userId);
        if(StringUtils.isNotBlank(robotOrder)){
            orderMap= GsonUtils.GSON.fromJson(robotOrder, new TypeToken<HashMap<String, Integer>>() {}.getType());
        }else{
            //第一次访问没有序号记录就全部默认显示第一个。另外开场语比较特殊有根据机器人名称定制
            orderMap.put(RobotOrdersTypeEnum.TALK_NAME.getValue(),1);
            orderMap.put(RobotOrdersTypeEnum.TALK_OPENING.getValue(),0);
            orderMap.put(RobotOrdersTypeEnum.TALK_LEAVE.getValue(),1);
        }
        return orderMap;
    }
    /**
     * 设置机器人名称和开场语的显示排序号
     * @Author Pbody
     * @Date 17:54 2020/5/30
     * @Param [userId]
     * @return java.lang.String
     **/
    private void setRobotOrders(final String userId,final String cmpDn,final HashMap<String,Integer> ordersMap){
        HashMap<String,Integer> newOrdersMap=new HashMap<>();
        /**机器人名称的显示序号设置**/
        //读取序号配置清单
        int robotLength = robotInfoBiz.getRobotByCmpDn(cmpDn).size();
        String robotVal=RobotOrdersTypeEnum.TALK_NAME.getValue();
        int valOrders=ordersMap.get(robotVal);
        //当前排序号小于总数，+1；若大于或相等则重新开始
        int newOrders=valOrders;
        if(valOrders<robotLength){
            newOrders=valOrders+1;
        }else{
            newOrders=1;
        }
        newOrdersMap.put(robotVal,newOrders);
        /**开场语显示序号设置**/
        String openingType=RobotOrdersTypeEnum.TALK_OPENING.getValue();
        newOrdersMap.put(openingType,ordersMap.get(openingType));
        if(robotLength==ordersMap.get(robotVal)){
            //开场语的切换规则：当机器人名称的排序号显示到了最后一位时，开场语才需要跟着循环切换
            newOrdersMap = setDictOrders(newOrdersMap,openingType,DictParentEnum.TALK_OPENING_WORDS.getValue(),0);
        }
        /**离场语的显示序号设置，离场在问答答案满足条件时才会触发最新的序号生成**/
        String leaveType=RobotOrdersTypeEnum.TALK_LEAVE.getValue();
        newOrdersMap.put(leaveType,ordersMap.get(leaveType));
        /**最后设置新的显示序号**/
        redisCacheUtil.hset(CacheEnum.ROBOT_WORDS_ORDERS.getValue(),userId,GsonUtils.GSON.toJson(newOrdersMap),0L);
    }

    /**
     * 设置开场语循环显示排序号
     * @Author Pbody
     * @Date 21:24 2020/5/30
     * @Param [ordersMap最新排序MAP, enumType排序枚举分类, dicType字段分类, defalutOrder默认的开始序号]
     * @return java.util.HashMap<java.lang.String,java.lang.Integer>
     **/
    private HashMap<String,Integer> setDictOrders(final HashMap<String,Integer> ordersMap,String enumType,
                                                  String dicType,int defalutOrder){
        HashMap<String,Integer> newOrdersMap = new HashMap<>();
        newOrdersMap.putAll(ordersMap);
        //设置下一句场景语循环
        int order=newOrdersMap.get(enumType);
        int total=dictItemService.findDictByParentId(dicType).size();
        //当前排序号小于总数，+1；若相等则重新开始
        int newOrders=order;
        if(order<total){
            newOrders=order+1;
        }else{
            newOrders=defalutOrder;
        }
        newOrdersMap.put(enumType,newOrders);
        return newOrdersMap;
    }


    /**
     * 默认获取最新一个的用户分配的机器人信息
     * @Author Pbody
     * @Date 1:43 2020/5/31
     * @Param [newRobot控制上目前会话在用的老的,userId, cmpDn]
     * @return net.zoneland.aitalk.dal.bean.RobotInfo
     **/
    private RobotInfo getNewRobotInfo(final boolean newRobot,final LoginUserPojo loginUserPojo,final boolean isCmpDn){
        RobotInfo robotInfo = null;
        List<RobotInfo> robotInfoList= new ArrayList<>();
        if(isCmpDn){
            List<RobotInfo> robotInfoList1 = robotInfoBiz.getRobotByCmpDn(loginUserPojo.getCompanyDN());
            for (RobotInfo robotInfo1 : robotInfoList1) {
                if(StringUtils.isBlank(robotInfo1.getDeptDn())){
                    robotInfoList.add(robotInfo1);
                }
            }
        }else {
            String[] deptArr = loginUserPojo.getDepartmentDN().split(",");
            StringBuffer deptDn = new StringBuffer("");
            if(deptArr.length > 1){
                deptDn.append(deptArr[deptArr.length - 2]).append(",").append(deptArr[deptArr.length - 1]);
                if(StringUtils.isNotBlank(CmpDnEnum.getCityByValue(deptDn.toString()))){
                    deptDn = new StringBuffer("");
                    deptDn.append(deptArr[deptArr.length - 3]).append(",").append(deptArr[deptArr.length - 2]).append(",").append(deptArr[deptArr.length - 1]);
                }
            }
            robotInfoList=robotInfoBiz.getRobotByDeptDn(deptDn.toString());
        }
        HashMap<String,Integer> ordersMap=getRobotOrders(loginUserPojo.getUserID());
        if(robotInfoList.size() < 1){
            return new RobotInfo();
        }
        int robotNameOrder=ordersMap.get(RobotOrdersTypeEnum.TALK_NAME.getValue());
        //若机器人配置被删除，当前序号小于总数则直接取，否则就重新记。总的规则是只认排序号位置不认数据。
        if(robotNameOrder>0&&robotNameOrder<=robotInfoList.size()){
            int oldIndex=0;
            if(newRobot){
                //获取下一个最新机器人信息
                oldIndex=robotNameOrder-1;
            }else{
                //获取当前聊天会话中的机器人信息，最新与总量相等
                if(robotNameOrder==1){
                    oldIndex=robotInfoList.size()-1;
                }else{
                    oldIndex=robotNameOrder-2;
                }
            }
            robotInfo=robotInfoList.get(oldIndex);
        }else{
            robotInfo=robotInfoList.get(0);
        }
        return robotInfo;
    }

    @Override
    public List<QuickNav> getQuickNav() {
        final List<String> list = redisCacheUtil.hGetAll(CacheEnum.QUICK_NAV.getValue());
        List<QuickNav> listAfterSort = list.stream().map(item -> GsonUtils.GSON.fromJson(item, QuickNav.class))
            .sorted(Comparator.comparing(QuickNav::getOrderId))
            .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(listAfterSort)) {
            return listAfterSort;
        }
        final QuickNavExample param = new QuickNavExample();
        param.setOrderByClause(" orderId asc ");
        return quickNavMapper.selectByExample(param);
    }

    @Override
    public List<DataCategory> getDataCategory() {
        try {
            return (List<DataCategory>)cache.get(CACHE_CATEGORY, () -> {
                final List<String> list = redisCacheUtil.hGetAll(CacheEnum.DATA_CATEGORY.getValue());
                if(CollectionUtils.isNotEmpty(list)) {
                    List<DataCategory> listAfterSort = list.stream()
                        .map(item -> GsonUtils.GSON.fromJson(item, DataCategory.class))
                        .sorted(Comparator.comparing(DataCategory::getSort))
                        .collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(listAfterSort)) {
                        return listAfterSort;
                    }
                }
                final DataCategoryExample param = new DataCategoryExample();
                param.setOrderByClause(" sort asc ");
                return dataCategoryMapper.selectByExample(param);
            });
        } catch (ExecutionException e) {
            LOGGER.error("getDataCategory error", e);
        }
        return Collections.emptyList();
    }

}
